﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.ComponentModel;
using System.Windows;
using ProxyViewModel;

namespace AutoViewModel.Tests {
	[TestClass]
	public class TestOfINotifyImplementation {

		public class A {
			public virtual string Property1 {
				get;
				set;
			}

			public virtual int Property2 {
				get;
				set;
			}
		}

		public class B : A {
			public virtual decimal Property3 {
				get;
				set;
			}
		}

		public class AI : INotifyPropertyChanged {

			public virtual string Property1 {
				get;
				set;
			}

			public virtual decimal Property2 {
				get;
				set;
			}

			#region INotifyPropertyChanged Members

			public event PropertyChangedEventHandler PropertyChanged;

			#endregion
		}

		public class BI : AI {
			public virtual decimal Property3 {
				get;
				set;
			}
		}

		public class ABaseTest {
			private string _prop1;
			public int _porp2;

			public bool Prop1SetterInvoked;
			public bool Prop1GetterInvoked;

			public bool Prop2SetterInvoked;
			public bool Porp2GetterInvoked;

			public virtual string Prop1 {
				get {
					Prop1GetterInvoked = true;
					return _prop1;
				}
				set {
					Prop1SetterInvoked = true;
					_prop1 = value;
				}
			}

			public virtual int Porp2 {
				get {
					Porp2GetterInvoked = true;
					return _porp2;
				}
				set {
					Prop2SetterInvoked = true;
					_porp2 = value;
				}
			}
		}

		public class SimplePropertyViewModel {
			private string _val;

			public virtual string ObservableProp1 {
				get;
				set;
			}

			internal string SimpleProp {
				set { _val = value; }
			}
		}

		[TestMethod]
		public void TestObjectWithNoINotifyPropertyChangedImplementation() {
			A myObject = ProxyViewModelFactory.CreateProxyViewModel<A>();

			Assert.IsTrue(myObject is INotifyPropertyChanged);

			int propertyChangedCallsCount = 0;

			(myObject as INotifyPropertyChanged).PropertyChanged += (s, e) => {
				Assert.IsTrue(e.PropertyName == "Property1" || e.PropertyName == "Property2");
				propertyChangedCallsCount++;
			};

			myObject.Property1 = "test";
			myObject.Property2 = 700300;

			// at this point PropertyChanged must have been called twice
			Assert.AreEqual(2, propertyChangedCallsCount, "PropertyChanged must be called twice here");

			Assert.AreEqual(myObject.Property1, "test");
			Assert.AreEqual(myObject.Property2, 700300);
		}

		[TestMethod]
		public void TestSecondLevelInheritanceAndTestObjectWithNoINotifyPropertyChangedImplementation() {
			B myObject = ProxyViewModelFactory.CreateProxyViewModel<B>();

			Assert.IsTrue(myObject is INotifyPropertyChanged);

			int propertyChangedCallsCount = 0;

			(myObject as INotifyPropertyChanged).PropertyChanged += (s, e) => {
				Assert.IsTrue(e.PropertyName == "Property1" || e.PropertyName == "Property2" || e.PropertyName == "Property3");
				propertyChangedCallsCount++;
			};

			myObject.Property1 = "test";
			myObject.Property2 = 700300;
			myObject.Property3 = 323;

			// at this point PropertyChanged must have been called twice
			Assert.AreEqual(3, propertyChangedCallsCount, "PropertyChanged must be called twice here");
			Assert.AreEqual(myObject.Property1, "test");
			Assert.AreEqual(myObject.Property2, 700300);
			Assert.AreEqual(myObject.Property3, 323);
		}

		[TestMethod]
		public void TestObjectWithNotifyPropertyChangedImplementation() {
			AI myObject = ProxyViewModelFactory.CreateProxyViewModel<AI>();

			Assert.IsTrue(myObject is INotifyPropertyChanged);

			int propertyChangedCallsCount = 0;

			(myObject as INotifyPropertyChanged).PropertyChanged += (s, e) => {
				Assert.IsTrue(e.PropertyName == "Property1" || e.PropertyName == "Property2");
				propertyChangedCallsCount++;
			};

			myObject.Property1 = "test";
			myObject.Property2 = 700300;

			// at this point PropertyChanged must have been called twice
			Assert.AreEqual(2, propertyChangedCallsCount, "PropertyChanged must be called twice here");

			Assert.AreEqual(myObject.Property1, "test");
			Assert.AreEqual(myObject.Property2, 700300);

		}

		[TestMethod]
		public void TestSecondLevelInheritanceAndTestObjectWithNotifyPropertyChangedImplementation() {
			BI myObject = ProxyViewModelFactory.CreateProxyViewModel<BI>();

			Assert.IsTrue(myObject is INotifyPropertyChanged);

			int propertyChangedCallsCount = 0;

			(myObject as INotifyPropertyChanged).PropertyChanged += (s, e) => {
				Assert.IsTrue(e.PropertyName == "Property1" || e.PropertyName == "Property2" || e.PropertyName == "Property3");
				propertyChangedCallsCount++;
			};

			myObject.Property1 = "test";
			myObject.Property2 = 700300;
			myObject.Property3 = 323;

			// at this point PropertyChanged must have been called twice
			Assert.AreEqual(3, propertyChangedCallsCount, "PropertyChanged must be called twice here");
			Assert.AreEqual(myObject.Property1, "test");
			Assert.AreEqual(myObject.Property2, 700300);
			Assert.AreEqual(myObject.Property3, 323);
		}

		[TestMethod]
		public void TestIfPropertyGettersAndSettersCalled() {
			ABaseTest myObject = ProxyViewModelFactory.CreateProxyViewModel<ABaseTest>();

			myObject.Prop1 = "temp1";
			myObject.Porp2 = 123;

			Assert.AreEqual(myObject.Prop1, "temp1");
			Assert.AreEqual(myObject.Porp2, 123);

			Assert.IsTrue(myObject.Prop1GetterInvoked && myObject.Prop1SetterInvoked);
			Assert.IsTrue(myObject.Porp2GetterInvoked && myObject.Prop2SetterInvoked);
		}

		[TestMethod]
		public void TestViewModelWithSimpleProperty() {
			SimplePropertyViewModel vm = ProxyViewModelFactory.CreateProxyViewModel<SimplePropertyViewModel>();

			vm.ObservableProp1 = "test";
			vm.SimpleProp = "test2";
	
			Assert.AreEqual(vm.ObservableProp1, "test");
		}
	}
}
